package cn.cxyxj.study110.a;

import cn.cxyxj.study110.entity.SysUser;
import cn.cxyxj.study110.entity.SysUserDetails;
import cn.cxyxj.study110.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 自定义投票器
 */
@Slf4j
@Component
public class CustomizeVoter implements AccessDecisionVoter<FilterInvocation> {


    @Override
    public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> attributes) {
        assert authentication != null;
        assert object != null;

        // 拿到当前请求url
        String requestUrl = object.getRequestUrl();
        log.info("自定义投票器，URI : {} {}", requestUrl);
        Object principal = authentication.getPrincipal();
        // 匿名用户访问，进行弃权投票
        if (principal instanceof String && "anonymousUser".equals(principal)) {
                return ACCESS_ABSTAIN;
        } else {
            SysUserDetails sysUserDetails = (SysUserDetails) principal;
            SysUser sysUser = sysUserDetails.getSysUser();
            // 从【所有接口 URL】缓存中获得，如果缓存中没有当前请求的 URL 记录，则说明该 URL 是不需要角色权限的，进行弃权投票
            boolean flag = RedisUtil.sHasKey("all-url", requestUrl);
            if(!flag){
                return ACCESS_ABSTAIN;
            }
            // 获得当前用户的接口权限信息
            Set<Object> redisSetUrl = RedisUtil.sGet(sysUser.getAccount() + ":" + sysUser.getId());
            if (Objects.isNull(redisSetUrl)) {
                return ACCESS_ABSTAIN;
            }
            Set<String> collect = redisSetUrl.stream().map(String::valueOf).collect(Collectors.toSet());
            // 拿到当前用户所具有的权限，与当前请求url进行匹配
            PathMatcher matcher = new AntPathMatcher();
            boolean match = collect.stream().anyMatch(u -> matcher.match(u, requestUrl));
            if (match) {
                // 授予权限票
                return ACCESS_GRANTED;
            } else {
                //授予拒绝票
                return ACCESS_DENIED;
            }
        }
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}